package com.gitee.wsl.mathematics.matrix.mat2

import com.gitee.wsl.mathematics.matrix.M
import com.gitee.wsl.mathematics.matrix.Matrix
import com.gitee.wsl.mathematics.matrix.MatrixD
import com.gitee.wsl.mathematics.matrix.MatrixF
import com.gitee.wsl.mathematics.matrix.MutableMatrix
import com.gitee.wsl.mathematics.matrix.N
import com.gitee.wsl.mathematics.matrix.SquareMatrix
import com.gitee.wsl.mathematics.vector.vec2.Vector2


interface Matrix2<T:Number,V: Matrix2<T, V, R>,R:Vector2<T,R>>:SquareMatrix<T,V,R>{

    override val rowCount: Int get() = 2
    override val colCount: Int get() = 2

    val m00: T get() = proxy[0]
    val m01: T get() = proxy[1]
    val m10: T get() = proxy[2]
    val m11: T get() = proxy[3]

    override val det get() = m00 * m11 - m01 * m10

    override fun create(values: List<T>): V = create(
        values[0],
        values[1],
        values[2],
        values[3]
    )

    fun create(m00: T, m01: T,
               m10: T, m11: T):V

    override val m: List<Vector2<T,R>>

    override val n: List<Vector2<T,R>>

    //override fun createVec(indexRage:IntRange) = createVec(indexRage.toList())

    override fun createVec(indexes:List<Int>): Vector2<T, R>

    fun createVec2(x:T,y:T):Vector2<T, R>

    override fun toMutable(): MutableMatrix2<T, V, R>

    fun copy(m00: T?=null, m01: T?=null,
             m10: T?=null, m11: T?=null):V 
    = create(
        m00 ?: this.m00,
        m01 ?: this.m01,
        m10 ?: this.m10,
        m11 ?: this.m11
    )
    
    override fun times(other: V) = create(
        m00 * other.m00 + m01 * other.m10, m00 * other.m01 + m01 * other.m11,
        m10 * other.m00 + m11 * other.m10, m10 * other.m01 + m11 * other.m11
    )

    override val adjoin: V
        get() = create(m11, -m01, -m10, m00)

   /* override fun inverse():V =
        adjoin().let{
            val a00 =it.m00
            val a01 =it.m01
            val a10 =it.m10
            val a11 =it.m10
            val det = m00 * a00 + m01 * a10
            if (det == zero) {
                throw IllegalArgumentException("Matrix determinant is zero:\n$this")
            }
            create(a00 / det, a01 / det, a10 / det, a11 / det)
        }*/

    operator fun component1() = m00
    operator fun component2() = m01
    operator fun component3() = m10
    operator fun component4() = m11


    override operator fun M.get(row: Int) = createVec(rowIndexes(row))

    override operator fun N.get(col: Int) = createVec(colIndexes(col))


}

interface Matrix2F<V: Matrix2<Float, V, R>,R:Vector2<Float,R>>: Matrix2<Float, V,R>, MatrixF<V,R>

interface Matrix2D<V: Matrix2<Double, V, R>,R:Vector2<Double,R>>: Matrix2<Double, V,R>, MatrixD<V,R>